<?php

namespace App\Kuafu\WaiMai\Model;

use App\Kuafu\Base\Model\Traits\KfSplitRelation;
use App\Kuafu\Base\Model\Traits\KfWaiMaiSplit;
use App\Kuafu\Common\Service\CommonService;
use App\Kuafu\Mybank\Service\CalcBrokerage\MybankCalcWaimaiBrokerageService;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Jobs\MybankCalcOrderPriceJob;
use App\Kuafu\Order\Model\OrderOperateRecordModel;
use App\Kuafu\Order\Service\OrderDb;
use App\Kuafu\Shop\Model\Shop;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use App\Kuafu\WaiMai\Service\BaseWaiMaiOrderService;
use Exception;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use App\Kuafu\Base\Model\BaseModel;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class WaiMaiOrderModel extends BaseModel
{
    use KfWaiMaiSplit;
    use KfSplitRelation;

    protected $connection = 'mysqlWaiMai';
    protected $table      = 'waimai_orders'; //表名
    protected $primaryKey = 'orderId';
    protected $fillable   = [
        'orderId',
        'brandId',
        'shopId',
        'sourceType',
        'serialNum',
        'originalPrice',
        'shouldPrice',
        'payPrice',
        'discountPrice',
        'shippingPrice',
        'originalShippingPrice',
        'packingPrice',
        'refundPrice',
        'refundPriceToUser',
        'activityExpenditure',
        'expectIncome',
        'orderStatus',
        'expectFast',
        'expectTime',
        'acceptTime',
        'completeTime',
        'senderName',
        'receiverName',
        'receiverPhone',
        'receiverAddress',
        'remark',
        'redPrice',
        'redLists',
        'senderPhone',
        'receiverPrivacyPhones',
        'fullReductionPrice',
        'platformPrice',
        'refundReason',
        'refundPic',
        'rejectReason',
        'otherPrice',
        'createdAt',
        'updatedAt',
        'invoiceStatus',
        'invoiceCanCancelCount',
        'isFinishFoods',
        'isPartRefund',
        'taxpayers',
        'brokeragePer',
        'brokerage',
        'divisionBillId',
        'isPartRefund',
        'taxpayers',
    ];

    public function shopRel(): Relation
    {
        return $this->hasOne(Shop::class, 'id', 'shopId');
    }

    // 仅关联菜品，不关联包装物
    public function orderDetailsRel(): Relation
    {
        $tableName = (new WaiMaiOrderDetailModel)->getBaseTable();
        $connect   = OrderDb::orderDbConnection(self::$splitShopId, OrderDb::DB_TYPE_WAIMAI);

        return $this->hasManyWithTable(WaiMaiOrderDetailModel::class, 'orderId', 'orderId', $tableName, $connect)
                    ->where('productType', WaiMaiOrderDetailModel::PRODUCT_TYPE_1)
                    ->orderBy('originalPrice');

    }

    // 关联所有菜+包装物
    public function orderDetailsRelTotal(): Relation
    {
        $tableName = (new WaiMaiOrderDetailModel)->getBaseTable();
        $connect   = OrderDb::orderDbConnection(self::$splitShopId, OrderDb::DB_TYPE_WAIMAI);

        return $this->hasManyWithTable(WaiMaiOrderDetailModel::class, 'orderId', 'orderId', $tableName, $connect)
                    ->orderBy('originalPrice');
    }

    /**
     * 部分退款日志
     * @return Relation
     * @throws \Exception
     */
    public function partRefundRel(): Relation
    {
        $tableName = (new WaiMaiPartRefundLogModel)->getBaseTable();
        $connect   = OrderDb::orderDbConnection(self::$splitShopId, OrderDb::DB_TYPE_WAIMAI);

        return $this->hasManyWithTable(WaiMaiPartRefundLogModel::class, 'orderId', 'orderId', $tableName, $connect)
                    ->orderByDesc('id');
    }

    public function getOrderStatusTextAttribute(): string
    {
        return WaiMaiDBEnum::ORDER_STATUS_TEXT[$this->orderStatus] ?? '';
    }

    public function getSourceTypeTextAttribute(): string
    {
        return CodeEnum::SOURCE_TYPES[$this->sourceType] ?? '';
    }

    public function getReceiverPrivacyPhoneArrAttribute(): array
    {
        return (array)json_decode($this->receiverPrivacyPhones, true);
    }

    public function getRefundPicArrAttribute(): array
    {
        return (array)json_decode($this->refundPic, true);
    }

    public function getPhoneCombineAttribute(): string
    {
        $arr = json_decode($this->receiverPrivacyPhones, true);
        if (!$arr) {
            return $this->receiverPhone;
        }

        if ($arr == '[]') {
            $arr = [];
        }

        $str = '';
        foreach ($arr as $v) {
            $str .= $v . ' / ';
        }

        $str = rtrim($str, ' / ');

        return $str . ' / ' . $this->receiverPhone;
    }

    public function getExpectTimeFormatAttribute(): string
    {
        $prefix = $this->expectFast ? "立即送达" : '预订单  期望 ';

        // 没时间，直接显示立即送达
        // 立即送达不加时间
        if (!$this->expectTime || $this->expectFast) {
            return $prefix;
        }

        // 预约当天
        if (date('Ymd') == date('Ymd', $this->expectTime)) {
            return $prefix . date('H:i', $this->expectTime);
        }

        // 预约今天以后
        return $prefix . date('m-d H:i', $this->expectTime);
    }

    public function getRefundStatusAttribute()
    {
        if ($this->orderStatus == WaiMaiDBEnum::ORDER_STATUS_6) {
            return WaiMaiDBEnum::REFUND_STATUS_1;
        }

        if ($this->orderStatus == WaiMaiDBEnum::ORDER_STATUS_7) {
            return WaiMaiDBEnum::REFUND_STATUS_2;
        }

        if ($this->isPartRefund == 1) {
            return WaiMaiDBEnum::REFUND_STATUS_3;
        }

        return WaiMaiDBEnum::REFUND_STATUS_0;
    }

    public function getTaxInfoAttribute(): array
    {
        if (!$this->taxpayers) {
            return [];
        }

        $arr = json_decode($this->taxpayers, true);
        if (!$arr) {
            return [];
        }

        return collect($arr)->map(function ($v, $k) {
            if (!$v) {
                return null;
            }

            return [
                'key'   => WaiMaiDBEnum::TAX_TEXT[$k] ?? '',
                'value' => $v,
            ];
        })->filter()->values()->toArray();
    }

    public function addData(array $data)
    {
        return self::suffix($data['shopId'])->create($data);
    }

    public function acceptOrder(int $acceptTime): int
    {
        return self::suffix($this->shopId)->where('orderId', $this->orderId)->update([
            'orderStatus' => WaiMaiDBEnum::ORDER_STATUS_2,
            'acceptTime'  => $acceptTime
        ]);
    }

    public function waitDeliver(string $senderName = '', string $sendPhone = ''): int
    {
        $updateData = [
            'orderStatus' => WaiMaiDBEnum::ORDER_STATUS_3
        ];
        if ($senderName || $sendPhone) {
            $updateData['senderName']  = $senderName;
            $updateData['senderPhone'] = $sendPhone;
        }
        return self::suffix($this->shopId)
                   ->where('orderId', $this->orderId)
                   ->update($updateData);
    }

    public function deliveringOrder(string $senderName, string $sendPhone): int
    {
        $updateData = [
            'orderStatus' => WaiMaiDBEnum::ORDER_STATUS_4
        ];
        if ($senderName || $sendPhone) {
            $updateData['senderName']  = $senderName;
            $updateData['senderPhone'] = $sendPhone;
        }
        return self::suffix($this->shopId)
                   ->where('orderId', $this->orderId)
                   ->update($updateData);
    }

    /**
     * 存储分账佣金信息
     */
    public function saveBrokerage(): void
    {
        try {
            MybankCalcOrderPriceJob::dispatch(
                $this->shopId,
                $this->orderId,
                CodeEnum::SOURCE_TYPE_WAIMAI
            )->onQueue(MybankCalcOrderPriceJob::$QUEUE_NAME);
        } catch (Exception $ex) {
            CommonService::fsLogException('【 队列入队 】【 网商外卖分账计算佣金 】', $ex,
                ['shopId' => $this->shopId, 'orderId' => $this->orderId], true);
        }

    }

    /**
     * 获取存储佣金的佣金总和
     *
     * @param int $startAt
     * @param int $endAt
     * @param int|null $divisionBillId
     * @param int|null $sourceType
     * @return mixed
     */
    public function getBrokerageSum(int $startAt, int $endAt, ?int $sourceType = 0, ?int $divisionBillId = 0)
    {
        return self::suffix($this->shopId)
                   ->where('shopId', $this->shopId)
                   ->where('orderStatus', WaiMaiDBEnum::ORDER_STATUS_5)
                   ->whereBetween('completeTime', [$startAt, $endAt])
                   ->when($sourceType !== null, function ($query) use ($sourceType) {
                       return $query->where('sourceType', $sourceType);
                   })
                   ->when($divisionBillId !== null, function ($query) use ($divisionBillId) {
                       return $query->where('divisionBillId', $divisionBillId);
                   })
                   ->sum('brokerage');
    }

    /**
     * 更新外卖订单的分佣ID
     *
     * @param int $startAt
     * @param int $endAt
     * @param int|null $divisionBillId
     * @param int|null $sourceType
     * @return mixed
     */
    public function updateDivisionBillId(int $startAt, int $endAt, int $sourceType, int $divisionBillId)
    {
        return self::suffix($this->shopId)
                   ->where('shopId', $this->shopId)
                   ->where('orderStatus', WaiMaiDBEnum::ORDER_STATUS_5)
                   ->whereBetween('completeTime', [$startAt, $endAt])
                   ->where('sourceType', $sourceType)
                   ->update([
                       'divisionBillId' => $divisionBillId
                   ]);
    }

    public function completeOrder(?int $completeTime, ?int $expectIncome = 0): int
    {
        $arr = ['orderStatus' => WaiMaiDBEnum::ORDER_STATUS_5,];
        if ($completeTime !== null) {
            $arr['completeTime'] = $completeTime;
        }

        if ($expectIncome) {
            $arr['expectIncome'] = $expectIncome;
        }

        return self::suffix($this->shopId)
                   ->where('orderId', $this->orderId)
                   ->update($arr);
    }

    public function cancelOrderFinish(): void
    {
        $order = self::suffix($this->shopId)
                     ->where('orderId', $this->orderId)->first();

        if (!$order) {
            return;
        }

        // 有部分退款记录
        if ($order->partRefundRel->count()) {

            $order->partRefundRel->each(function ($partRefundRel) use (&$order) {

                // 把各种金额重写回去
                // 营业额
                $order->originalPrice += $partRefundRel->originalPrice;

                // 用户支付金额
                $order->payPrice += $partRefundRel->payPrice;

                // 预计收入
                $order->expectIncome += $partRefundRel->expectIncome;

                // 包装费
                $order->packingPrice += $partRefundRel->packingPrice;
            });
        }

        $order->orderStatus       = WaiMaiDBEnum::ORDER_STATUS_7;
        $order->refundPrice       = $order->payPrice;
        $order->refundPriceToUser = $order->payPrice;
        $order->isPartRefund      = WaiMaiDBEnum::IS_PART_REFUND_0; // 全部退款
        $order->save();
    }

    public function applyCancelOrder(
        int $orderStatus,
        string $reason,
        string $pics,
        int $isPartRefund = WaiMaiDBEnum::IS_PART_REFUND_0
    ): int {
        $arr = [
            'orderStatus'  => $orderStatus,
            'refundReason' => $reason,
            'refundPic'    => $pics,
        ];

        if ($isPartRefund == WaiMaiDBEnum::IS_PART_REFUND_1) {
            $arr['isPartRefund'] = WaiMaiDBEnum::IS_PART_REFUND_1;
        }

        return self::suffix($this->shopId)
                   ->where('orderId', $this->orderId)
                   ->update($arr);
    }

    public function recallCancelOrder(int $orderStatus, string $reason = ''): int
    {
        return self::suffix($this->shopId)
                   ->where('orderId', $this->orderId)
                   ->update([
                       'orderStatus'  => $orderStatus,
                       'rejectReason' => $reason
                   ]);
    }

    public function rejectReason(string $rejectReason): int
    {
        return self::suffix($this->shopId)
                   ->where('orderId', $this->orderId)
                   ->update(['rejectReason' => $rejectReason]);
    }

    /**
     * 部分退款完成
     * @param bool $doPart true退款 false取消退款
     * @param int $platformRefundPrice
     * @param int $orderStatus
     * @param int $userRefundPrice
     * @param int $packingPrice
     * @param int $originalPrice
     * @param int|null $nowIncomes
     */
    public function partRefundFinish(
        bool $doPart,
        int $platformRefundPrice,
        int $orderStatus,
        int $userRefundPrice = 0,
        int $packingPrice = 0,
        int $originalPrice = 0,
        ?int $nowIncomes = null,
        int $reduceIncomes = 0
    ) {
        $order = self::suffix($this->shopId)->where('orderId', $this->orderId)->first();

        $order->orderStatus = $orderStatus;

        if ($doPart) {

            // 商家退款金额
            if ($platformRefundPrice != 0) {
                $order->refundPrice += $platformRefundPrice;
            } else {
                $order->refundPrice += $reduceIncomes;
            }

            // 用户收到的退款金额
            $order->refundPriceToUser += $userRefundPrice;

            // 营业额
            $order->originalPrice -= $originalPrice;

            // 用户支付金额
            $order->payPrice -= $userRefundPrice;

            // 预计收入
            if ($nowIncomes !== null) {
                $order->expectIncome = $nowIncomes;
            } else {
                $order->expectIncome -= $reduceIncomes;
            }

            // 包装费
            $order->packingPrice -= $packingPrice;

            $order->isPartRefund = WaiMaiDBEnum::IS_PART_REFUND_1;

            // 日志记录 add
            WaiMaiPartRefundLogModel::suffix($this->shopId)->add(
                $this->shopId,
                $this->orderId,
                BaseWaiMaiOrderService::$callBackId ?? 0,
                $originalPrice,
                $userRefundPrice,
                $reduceIncomes,
                $packingPrice,
            );

        } else {
            $order->isPartRefund = WaiMaiDBEnum::IS_PART_REFUND_0;
        }

        $order->save();
    }

    public static function finishFoods(int $orderId, int $shopId, int $isFinishFoods): int
    {
        return self::suffix($shopId)
                   ->where('orderId', $orderId)
                   ->update(['orderStatus' => WaiMaiDBEnum::ORDER_STATUS_3, 'isFinishFoods' => $isFinishFoods]);
    }

    public static function invoiceStatusUpdate(int $orderId, int $shopId, int $invoiceStatus)
    {
        return self::suffix($shopId)->where('orderId', $orderId)->update(['invoiceStatus' => $invoiceStatus]);
    }

    public static function reduceInvoiceCancelCount(int $orderId, int $shopId)
    {
        return self::suffix($shopId)->where('orderId', $orderId)
                   ->update(['invoiceCanCancelCount' => DB::raw('invoiceCanCancelCount-1')]);
    }

    public static function editAcceptAdminName(int $orderId, string $acceptAdminName)
    {
        $shopId = WaiMaiOrderIdShopIdMappingModel::getShopId($orderId);
        return self::suffix($shopId)->where('orderId', $orderId)->update(['acceptAdminName' => $acceptAdminName]);
    }

    public function orderOperateRecordRel()
    {
        return $this->hasMany(OrderOperateRecordModel::class, 'orderId', 'orderId');
    }

    /**
     * 调整expectIncome，同步更新discountPrice、otherPrice
     * @return $this
     */
    public function changeExpectIncomeAffect(bool $doSave = true)
    {
        // 优惠金额 = 菜品原价合计 + 包装费 - 营业收入
        $this->discountPrice = $this->originalPrice - $this->originalShippingPrice - $this->expectIncome;

        // 其他支出 = 菜品原价合计 + 包装费 - 营业收入 - 平台服务费 - 商家活动支出
        $this->otherPrice = $this->discountPrice - $this->platformPrice - $this->activityExpenditure;

        if ($doSave) {
            $this->save();
        }

        return $this;
    }


    /**
     * 订单已拒单
     * @param int $updatedAt
     * @return int
     */
    public function refuseOrder(int $updatedAt): int
    {
        return self::suffix($this->shopId)->where('orderId', $this->orderId)->update([
            'orderStatus' => WaiMaiDBEnum::ORDER_STATUS_8,
            'updatedAt'  => $updatedAt
        ]);
    }

}
